/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package me.zhengjie.modules.enrstu.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.enrstu.domain.ChildrenInformation;
import me.zhengjie.modules.enrstu.domain.ReviewInformation;
import me.zhengjie.modules.enrstu.domain.ReviewInformationLog;
import me.zhengjie.modules.enrstu.domain.School;
import me.zhengjie.modules.enrstu.repository.ChildrenInformationRepository;
import me.zhengjie.modules.enrstu.repository.ManageRepository;
import me.zhengjie.modules.enrstu.repository.SchoolRepository;
import me.zhengjie.modules.enrstu.service.ManageService;
import me.zhengjie.modules.enrstu.service.ReviewInformationLogService;
import me.zhengjie.modules.enrstu.service.dto.*;
import me.zhengjie.modules.enrstu.service.enums.ReviewResult;
import me.zhengjie.modules.enrstu.service.enums.ReviewStage;
import me.zhengjie.modules.enrstu.service.enums.ReviewStatus;
import me.zhengjie.modules.enrstu.repository.ReviewInformationRepository;
import me.zhengjie.modules.enrstu.service.ReviewInformationService;
import me.zhengjie.modules.enrstu.service.mapstruct.ReviewInformationMapper;
import me.zhengjie.modules.system.domain.Dept;
import me.zhengjie.modules.system.domain.User;
import me.zhengjie.modules.system.repository.DeptRepository;
import me.zhengjie.modules.system.repository.UserRepository;
import me.zhengjie.utils.*;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.*;

/**
* @website https://eladmin.vip
* @description 服务实现
* @author yyx
* @date 2024-11-01
**/
@Slf4j
@Service
@RequiredArgsConstructor
public class ReviewInformationServiceImpl implements ReviewInformationService {
    private final ReviewInformationRepository reviewInformationRepository;
    private final ReviewInformationMapper reviewInformationMapper;
    private final ReviewInformationLogService reviewInfoLogService;
    private final ChildrenInformationRepository chdRepository;
    private final SchoolRepository schoolRepository;
    private final UserRepository userRepository;
    private final DeptRepository deptRepository;
    private final ManageService manageService;


    @Transactional
    public ReviewInformationDto findById(String id) {
        ReviewInformation reviewInformation = reviewInformationRepository.findById(id).orElseGet(ReviewInformation::new);
        ValidationUtil.isNull(reviewInformation.getId(), "ReviewInformation", "id", id);
        return reviewInformationMapper.toDto(reviewInformation);
    }
    
    @Override
    public void download(HttpServletResponse response) {
        //获取录取列表，传参为null，导出不需要进行条件查询
        List<ReviewAlreadyOrAcceptedInfoListDto> reviewAcceptedInfoList = reviewInformationRepository.
                findReviewAcceptedInfoList(null, null, null, null, null);
        log.info("导出录取列表，共{}条数据", reviewAcceptedInfoList);
        List<Map<String, Object>> list = new ArrayList<>();
        for (ReviewAlreadyOrAcceptedInfoListDto reviewInformation : reviewAcceptedInfoList) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("适龄儿童姓名", reviewInformation.getChildrenName());
            map.put("身份证号", reviewInformation.getChildrenIdentityCard());
            map.put("归属学区", reviewInformation.getSchoolDistrictName());
            map.put("就近入学学校", reviewInformation.getSchoolName());
            map.put("提交时间", reviewInformation.getSubCreate());
            map.put("审核时间", reviewInformation.getRepCreate());
            map.put("复审ID", reviewInformation .getReviewPersonId());
            map.put("状态", reviewInformation.getReviewStatus());
            list.add(map);
        }
        try {
            FileUtil.downloadExcel(list, response);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public ReviewInformation create(String signUpReportInfoId) {
        //调用项目接口获取当前用户对应的部门的项目信息，判断是否在初审或者复审时间段阶段
        log.info("上送signUpReportInfoId是否为空：{}", signUpReportInfoId);
        ReviewInformation reviewInfoNew = new ReviewInformation();
        //设置环节：提交审核
        reviewInfoNew.setId(IdUtil.simpleUUID());
        reviewInfoNew.setChildId(signUpReportInfoId);
        //修改提交审核次数
        reviewInfoNew.setReviewNum(0L);
        //驳回处理：判断儿童id是否存在审核表，如果存在则删除
        if (reviewInformationRepository.existsByChildId(signUpReportInfoId)){
            ReviewInformation reviewInfoPast = reviewInformationRepository.findByChildId(signUpReportInfoId);
            log.info("驳回处理根据儿童id获取旧的审核记录reviewInfoPast：{}", reviewInfoPast);
            //判断是否为重复审核
            if (!reviewInfoPast.getReviewStage().equals(ReviewStatus.NOT_PASSED.getDescription()) && !reviewInfoPast.getReviewResult().equals(ReviewResult.REJECTED.getDescription())){
                throw new BadRequestException("请勿重复提交审核");
            }
            //赋值：仅保存id、儿童id、审核次数、创建时间、修改时间
            long reviewNum = reviewInfoPast.getReviewNum() ;
            reviewInfoNew.setId(reviewInfoPast.getId());
            reviewInfoNew.setChildId(reviewInfoPast.getChildId());
            reviewInfoNew.setReviewNum(++reviewNum);
            reviewInfoNew.setGmtCreate(reviewInfoPast.getGmtCreate());
            reviewInfoNew.setGmtModified(reviewInfoPast.getGmtModified());
            log.info("驳回处理赋值处理后的结果reviewInfoNew：{}", reviewInfoNew);
        }

        reviewInfoNew.setReviewStage(ReviewStage.SUBMIT.getDescription());
        reviewInfoNew.setReviewResult(ReviewResult.SUBMIT.getDescription());

        //保存提交至明细
        this.reviewInfoLogSave(reviewInfoNew);
        log.info("保存提交审核记录至明细表中去：{}", reviewInfoNew);
        //设置环节：初审
        reviewInfoNew.setReviewStage(ReviewStage.SCHOOL_REVIEW.getDescription());
        reviewInfoNew.setReviewStatus(ReviewStatus.FIR_REVIEW.getDescription());
        log.info("保存提待初审记录至审核表中去：{}", reviewInfoNew);
        return reviewInformationRepository.save(reviewInfoNew);
    }

    @Override
    @Transactional
    public void review(ReviewOrAcceptedHandler reviewOrAcceptedHandler){

        /** 逻辑分析
        一.判断：
         1.当前环节与操作人是否匹配->初审：学生意向学校的操作员，复审:意向学校的直属教育局，录取：此接口不支持，不匹配则提示当前环节为xxx,不允许xxx进行审核，TODO:录取参照
         2.驳回状态->只能重新提交，不允许学校再次审核，退回状态->只能重新提交，不允许教育局再次审核
         3.若当前环节拒绝同一学校/教育局不同操作员重复修改已审核记录，
         4.当前状态为待初审审或者待复审时，对于上送的操作进行校验。初审：通过/驳回，复审：通过/退回初审
         5.调用项目接口获取当前用户对应的部门的项目信息，判断是否在初审或者复审时间段阶段
        二、审核
            1.将当前状态进行修改为已审核状态，并保存明细表：操作内容，状态，操作结果，操作人id，审核时间，然后 将当前环节修改为下一环节待审核状态，并保存审核表：环节，操作内容，状态，操作结果
            2.操作为驳回时，无需进行环节流转
         */
        //根据审核id获取当前审核记录，通过儿童id获取儿童信息表中的意向学校信息
        ManageDto mangeInfo = this.getMangeInfo();
        ReviewInformation reviewInfo = reviewInformationMapper.toEntity(findById(reviewOrAcceptedHandler.getReviewId()));
        ChildrenInformation chInfo = chdRepository.findById(reviewInfo.getChildId()).orElseGet(ChildrenInformation::new);
        School school = schoolRepository.findById(chInfo.getSchoolId()).orElseGet(School::new);
        //根据当前人id获取当前人信息中的部门
        User user = userRepository.findById(SecurityUtils.getCurrentUserId()).orElseGet(User::new);
        log.info("当前用户部门：{}", user.getDept().getId());
        log.info("学校部门：{}", school.getDeptId());
        log.info("操作结果：{}", reviewOrAcceptedHandler.getReviewResult());
        log.info("操作结果比对参数：{}", ReviewResult.APPROVED.getResult());
        log.info("审核记录信息：{}", reviewInfo);

        //判断是否为初审、退回初审或复审，以及其他：如录取状态此接口不允许操作-
        if (ObjectUtil.equal(reviewInfo.getReviewStatus(), ReviewStatus.FIR_REVIEW.getDescription())||ObjectUtil.equal(reviewInfo.getReviewStatus(), ReviewStatus.RETURNED.getDescription())){
            if (DateUtils.compare(mangeInfo.getPmfSchoolCheckStartTime()) > 0){
                throw new BadRequestException("学校初审时间未开始");
            }
            if (DateUtils.compare(mangeInfo.getPmfSchoolCheckEndTime()) < 0){
                throw new BadRequestException("学校初审时间已开始");
            }
            //待初审操作
            //判断部门是否匹配：否->您无权审核当前记录。是->  正常审核
            if (!user.getDept().getId().equals(school.getDeptId())){
                throw new BadRequestException("请确认账号的操作权限，当前账号无权审核此记录！");
            }

            if ( ObjectUtil.notEqual(reviewOrAcceptedHandler.getReviewResult(), ReviewResult.APPROVED.getResult())
                    && ObjectUtil.notEqual(reviewOrAcceptedHandler.getReviewResult(), ReviewResult.REJECTED.getResult())){
                throw new BadRequestException("请确认审核操作类型，当前记录仅支持通过或驳回操作！");
            }
            //保存明细前的预制处理
            this.logSavaPrepare(reviewInfo, reviewOrAcceptedHandler);
            //判断审核操作若为通过时的处理：将环节流转至下一环节保存至审核明细表
            if ( ObjectUtil.equal(reviewOrAcceptedHandler.getReviewResult(), ReviewResult.APPROVED.getResult())){
                reviewInfo.setReviewStage(ReviewStage.EDUCATION_BUREAU_REVIEW.getDescription());
                reviewInfo.setReviewStatus(ReviewStatus.REP_REVIEW.getDescription());
                log.info("待复审审核记录保存至审核记录表：{}", reviewInfo);
                reviewInformationRepository.save(reviewInfo);
            }else {
                reviewInfo.setReviewStatus(ReviewStatus.NOT_PASSED.getDescription());
                reviewInfo.setReviewResult(ReviewResult.REJECTED.getDescription());
                log.info("驳回审核记录保存至审核记录表：{}", reviewInfo);
                reviewInformationRepository.save(reviewInfo);

            }
        } else if (ObjectUtil.equal(reviewInfo.getReviewStatus(),ReviewStatus.REP_REVIEW.getDescription())) {
            if (DateUtils.compare(mangeInfo.getPmfEducationCheckStartTime()) > 0){
                throw new BadRequestException("教育局/教育委员会复审时间未开始");
            }
            if (DateUtils.compare(mangeInfo.getPmfEducationCheckEndTime()) < 0){
                throw new BadRequestException("教育局/教育委员会复审时间已结束");
            }
            //待复审操作
            //根据意向学校id获取直属教育局部门信息。判断部门是否匹配，否->您无权审核当前记录。
            Dept dept = deptRepository.findById(Long.valueOf(school.getSchoolEduId())).orElseGet(Dept::new);
            if (!user.getDept().getId().equals(dept.getId())){
                throw new BadRequestException("请确认账号的操作权限，当前账号无权审核此记录！");
            }

            if ( ObjectUtil.notEqual(reviewOrAcceptedHandler.getReviewResult(), ReviewResult.APPROVED.getResult())
                    && ObjectUtil.notEqual(reviewOrAcceptedHandler.getReviewResult(), ReviewResult.RETURNED.getResult())){
                throw new BadRequestException("请确认审核操作类型，当前记录仅支持通过或退回初审操作！");
            }
            //保存明细前的预制处理
            this.logSavaPrepare(reviewInfo, reviewOrAcceptedHandler);
            //判断审核操作若为通过时的处理：将环节流转至下一环节保存至审核明细表
            if ( ObjectUtil.equal(reviewOrAcceptedHandler.getReviewResult(), ReviewResult.APPROVED.getResult())){
                reviewInfo.setReviewStage(ReviewStage.ADMITTED.getDescription());
                reviewInfo.setReviewStatus(ReviewStatus.NOT_ADMITTED.getDescription());
                log.info("待录取审核记录保存至审核记录表：{}", reviewInfo);
                reviewInformationRepository.save(reviewInfo);
            }
            if ( ObjectUtil.equal(reviewOrAcceptedHandler.getReviewResult(), ReviewResult.RETURNED.getResult())){
                reviewInfo.setReviewStage(ReviewStage.SCHOOL_REVIEW.getDescription());
                reviewInfo.setReviewStatus(ReviewStatus.FIR_REVIEW.getDescription());
                log.info("待录取退回初审记录保存至审核记录表：{}", reviewInfo);
                reviewInformationRepository.save(reviewInfo);
            }
        }else{
            //判断：当前记录若状态以为驳回，则提示等待家长重新提交审核
            if (ObjectUtil.equal(reviewInfo.getReviewResult(),ReviewResult.RETURNED.getDescription())){
                throw new BadRequestException("请确认当前记录状态，当前状态不允许进行复审操作,待学校重新审核！");
            }
            //拦截上送异常状态数据
            throw new BadRequestException("请确认当前记录状态，该状态不允许进行审核操作！");
        }
    }
    @Override
    @Transactional
    public void accepted(List<ReviewOrAcceptedHandler> acceptedHandler){
        /** 逻辑分析
         一.判断：
         1.当前操作人与当前审核记录中的意向学校的部门进行匹配：否->您无权操作此记录。是->正常操作
         2.录取操作只能在环节为录取时，进行操作，否则不通过
         3.当前记录若状态以为已录取，则不能重复录取
         4.调用项目接口获取当前用户对应的部门的项目信息，判断是否在录取时间段
         二、审核
         1.将当前状态修改为已录取状态，并保存明细表：操作内容，状态，操作结果，操作人id，审核时间，无需将当前状态修改为下一环节，本状态为最终状态，直接在保存记录表即可
         */
        if (ObjectUtil.isEmpty(acceptedHandler)){
            throw new BadRequestException("录取失败，请至少上送一条录取数据！");
        }
        acceptedHandler.forEach(accepted -> {
            //获取记录和当前操作人信息
            ReviewInformation reviewInfo = reviewInformationMapper.toEntity(findById(accepted.getReviewId()));
            ChildrenInformation chInfo = chdRepository.findById(reviewInfo.getChildId()).orElseGet(ChildrenInformation::new);
            Long schoolId = schoolRepository.findById(chInfo.getSchoolId()).orElseGet(School::new).getDeptId();
            //根据当前人id获取当前人信息中的部门
            User user = userRepository.findById(SecurityUtils.getCurrentUserId()).orElseGet(User::new);

            if ( ObjectUtil.notEqual(accepted.getReviewResult(), ReviewResult.ADMITTED.getResult())){
                throw new BadRequestException("请确认审核操作类型，当前记录仅支持录取操作！");
            }
            //判断：当前操作人与当前审核记录中的意向学校的部门进行匹配
            if (!user.getDept().getId().equals(schoolId)){
                throw new BadRequestException("请确认账号的操作权限，当前账号无权审核此记录！");
            }
            //判断：录取操作只能在环节为录取时，进行操作
            if (ObjectUtil.notEqual(reviewInfo.getReviewStage(),ReviewStage.ADMITTED.getDescription())){
                throw new BadRequestException("请确认当前记录状态，当前状态不允许进行录取操作！");
            }
            //判断：当前记录若状态以为已录取，则不能重复录取
            if (ObjectUtil.equal(reviewInfo.getReviewStatus(),ReviewStatus.ADMITTED.getDescription())){
                throw new BadRequestException("请确认当前记录状态，当前状态不允许进行重复录取操作！");
            }
            log.info("已录取记录保存至审核记录表：{}", reviewInfo);
            this.logSavaPrepare(reviewInfo, accepted);
            reviewInformationRepository.save(reviewInfo);

        });
    }

    @Override
    public ReviewInformationDto findRwDynamicsList(Long dept,boolean isRepeatedReview) {

        dept = isRepeatedReview ? 26L : 25L;//TODO:测试
        return isRepeatedReview ? reviewInformationMapper.toDto(reviewInformationRepository.findRwWaitRepDynamicsList(String.valueOf(dept)).get(0)):
                reviewInformationMapper.toDto(reviewInformationRepository.findReWaitDynamicsList(dept).get(0));
    }


    @Override
    public PageResult<ReviewWaitInfoListDto> findReviewWaitInfoList(ReviewWaitInfoQueryCriteria resources, Pageable pageable) {
        //获取教育局or学校待审核列表
        List<ReviewWaitInfoListDto> pages = reviewInformationRepository.findReviewWaitInfoList(resources.getChildrenName(),
                resources.getChildrenIdentityCard(),
                resources.getSchoolDistrictName(),
                resources.getSchoolName(),
                resources.getIsRepeatedReview());
        //分页操作
        return  PageUtil.toPage(pages,pages.size());
    }

    @Override
    public PageResult<ReviewAlreadyOrAcceptedInfoListDto> findReviewAlreadyInfoList(ReviewAlreadyOrAcceptedInfoQueryCriteria resources,Pageable pageable) {
        //获取教育局or学校已审核列表
        List<ReviewAlreadyOrAcceptedInfoListDto> pages = reviewInformationRepository.findReviewAlreadyInfoList(resources.getChildrenName(),
                resources.getChildrenIdentityCard(),
                resources.getSchoolDistrictName(),
                resources.getSchoolName(),
                resources.getReviewStatus(),
                resources.getIsRepeatedReview()
                );
        log.info("已录取记录查询：{}", pages);
        //分页操作
        return  PageUtil.toPage(pages,pages.size());
    }

    @Override
    public PageResult<ReviewAlreadyOrAcceptedInfoListDto> findReviewAcceptedInfoList(ReviewAlreadyOrAcceptedInfoQueryCriteria resources,Pageable pageable) {
        //获取录取列表
        List<ReviewAlreadyOrAcceptedInfoListDto> pages = reviewInformationRepository.findReviewAcceptedInfoList(resources.getChildrenName(),
                resources.getChildrenIdentityCard(),
                resources.getSchoolDistrictName(),
                resources.getSchoolName(),
                resources.getReviewStatus()
        );
        //分页操作
        return  PageUtil.toPage(PageUtil.paging(pageable.getPageNumber(), pageable.getPageSize(), pages), reviewInformationRepository.countAccepted(resources.getIsRepeatedReview()));
    }


    /**
     * 审核明细保存
     * @param reviewInformation /
     */
    private void  reviewInfoLogSave(ReviewInformation reviewInformation) {

        log.info("审核明细reviewInformation:{}", reviewInformation);
        ReviewInformationLog reviewInformationLog = new ReviewInformationLog();
        BeanUtils.copyProperties(reviewInformation,reviewInformationLog );
        log.info("审核明细reviewInformationLog:{}", reviewInformationLog);
        reviewInformationLog.setReviewId(reviewInformation.getId());
        if (!ObjectUtil.equal(reviewInformation.getReviewResult(), ReviewResult.SUBMIT.getDescription())){
            reviewInformationLog.setReviewPersonId(String.valueOf(SecurityUtils.getCurrentUserId()));
            reviewInformationLog.setReviewTime(new Timestamp(System.currentTimeMillis()));
        }
        reviewInformationLog.setReviewNum(reviewInformation.getReviewNum());
        log.info("审核明细reviewInformationLog:{}", reviewInformationLog);
        reviewInfoLogService.create(reviewInformationLog);

    }
    /**保存明细前的预制处理*/
    private void logSavaPrepare(ReviewInformation reviewInfo,ReviewOrAcceptedHandler reviewOrAcceptedHandler){
        ReviewResult reviewResult = ReviewResult.fromResult(reviewOrAcceptedHandler.getReviewResult());
        if (reviewResult == null) {
            throw new BadRequestException("参数上送错误");
        }
        switch (reviewResult) {
            case APPROVED:
                //将操作结果为通过，把当前记录保存至明细表中:操作内容，状态，操作结果，操作人id，审核时间
                reviewInfo.setReviewStatus(ReviewStatus.PASSED.getDescription());
                reviewInfo.setReviewResult(ReviewResult.APPROVED.getDescription());
                reviewInfo.setReviewComments(reviewOrAcceptedHandler.getReviewComments());
                this.reviewInfoLogSave(reviewInfo);
                log.info("审核明细reviewInfo:{}", reviewInfo);
                break;
            case RETURNED:
                reviewInfo.setReviewStatus(ReviewStatus.RETURNED.getDescription());
                reviewInfo.setReviewResult(ReviewResult.RETURNED.getDescription());
                reviewInfo.setReviewComments(reviewOrAcceptedHandler.getReviewComments());
                this.reviewInfoLogSave(reviewInfo);
                break;
            case ADMITTED:
                reviewInfo.setReviewStatus(ReviewStatus.ADMITTED.getDescription());
                reviewInfo.setReviewResult(ReviewResult.ADMITTED.getDescription());
                reviewInfo.setReviewComments(reviewOrAcceptedHandler.getReviewComments());
                this.reviewInfoLogSave(reviewInfo);
                break;
            case REJECTED:
                reviewInfo.setReviewStatus(ReviewStatus.NOT_PASSED.getDescription());
                reviewInfo.setReviewResult(ReviewResult.REJECTED.getDescription());
                reviewInfo.setReviewComments(reviewOrAcceptedHandler.getReviewComments());
                this.reviewInfoLogSave(reviewInfo);
                break;
            default:
                throw new BadRequestException("Invalid field name: " + reviewResult.name());
        }
    }

    /**获取当前用户对应所属的招生项目信息*/
    private ManageDto getMangeInfo() {
        ManageDto sysUserStartMg = manageService.findSysUserStartMg();
        if (ObjectUtil.isNull(sysUserStartMg.getId())){
            throw new BadRequestException("当前没有可进行填报的招生项目");
        }
        log.info("当前用户对应项目信息:{}", sysUserStartMg);
        return sysUserStartMg;
    }
}